#include "EControllerQtTree.h"
#include "DefineCommon.h"
#include "ECommand.h"
#include "EController.h"
#include "EItem.h"
#include "EItemManager.h"
#include "EString.h"
#include "qmap.h"
#include "qtreewidget.h"
#include <ECommandManager.h>
#include <cstdint>


class QTreeItemExtended : public QTreeWidgetItem
{
public:
    /*value to index EItemPtr*/
    EItemPtr m_item;
};

class VisitorForQtTreeTravel : public EItemVisitor
{
public:
    VisitorForQtTreeTravel(){}
    virtual ~VisitorForQtTreeTravel(){}

    QTreeWidget* m_treeWidget;
    bool m_ifRefreshing = false;

    virtual bool handleEItem(EItemPtr item, int depth, EItemPtr parentItem)
    {
        //Get or create QTreeItemExtended
        intptr_t itemQtPtr = item->getAttached();
        if(m_ifRefreshing == true)
        {
            itemQtPtr = NULL;
        }

        QTreeItemExtended* treeItem = NULL;
        if(itemQtPtr == NULL && item->getIfShownInUI())
        {
            treeItem = new QTreeItemExtended;
            treeItem->m_item = item;
            item->setAttached((intptr_t)treeItem);
        }
        else if(itemQtPtr != NULL)
        {
            treeItem = (QTreeItemExtended*)itemQtPtr;
        }

        //syn name of treeItem and item
        EString name = item->getName();
        treeItem->setText(0, name.data());

        //get parent QTreeItemExtended
        QTreeItemExtended* treeItemParent = NULL;
        if(depth == 0)
        {
            //so treeItem is related to root item
            this->m_treeWidget->addTopLevelItem(treeItem);
        }
        else 
        {
            treeItemParent = (QTreeItemExtended*)parentItem->getAttached();
            treeItemParent->addChild(treeItem);
        }

        return true;
    }
protected:
};

EControllerQtTree::EControllerQtTree()
{
}

EControllerQtTree::~EControllerQtTree()
{
}

void EControllerQtTree::setTreeWidget(QTreeWidget* w)
{
    this->m_treeWidget = w;
    this->buildConnect();

}
    
void EControllerQtTree::refresh()
{
    this->clearConnect();
    this->m_treeWidget->clear();

    VisitorForQtTreeTravel visitor;
    visitor.m_ifRefreshing = true;
    visitor.m_treeWidget = this->m_treeWidget;
    visitor.travelEItem(this->getRootItem());
    this->buildConnect();
}


EItemPtr EControllerQtTree::addItem(EItemPtr typeItem)
{
    EItemPtr newItem = EController::addItem(typeItem);
    if(newItem == nullptr)
    {
        return newItem;
    }

    
    EItemPtr parent = newItem->getParent(newItem->getParentCount()-1);
    VisitorForQtTreeTravel visitor;
    visitor.handleEItem(newItem, -1, parent);

    this->m_treeWidget->expandItem(this->getTreeItemByEItemPtr(parent));

    return newItem;
}



EItemPtr EControllerQtTree::copyItem(EItemPtr item)
{
    EItemPtr newItem = EController::copyItem(item);
    if(newItem == nullptr)
    {
        return newItem;
    }
    
    EItemPtr parent = newItem->getParent(newItem->getParentCount()-1);
    VisitorForQtTreeTravel visitor;
    visitor.handleEItem(newItem, -1, parent);

    // this->m_treeWidget->expandItem(this->getTreeItemByEItemPtr(parent));

    return newItem;
}

void EControllerQtTree::deleteItem()
{
    EItemPtr item = this->getSelectedItem();

    bool result = EController::deleteItem(item);
    if(result == true)
    {
        QTreeWidgetItem* treeItem = this->getTreeItemByEItemPtr(item);
        QTreeWidgetItem* treeParent = treeItem->parent();
        treeParent->removeChild(treeItem);
    }
}



EItemPtr EControllerQtTree::getEItemByTreeItemPtr(QTreeWidgetItem* treeItem)
{
    EItemPtr result = nullptr;
    if(treeItem != NULL)
    {
        QTreeItemExtended* extended = (QTreeItemExtended*)treeItem;
        result = extended->m_item;
    }
    return result;
}

QTreeWidgetItem* EControllerQtTree::getTreeItemByEItemPtr(const EItemPtr& itemPtr)
{
    QTreeWidgetItem* result = NULL;
    if(itemPtr != nullptr)
    {
        result = (QTreeWidgetItem*)itemPtr->getAttached();
    }

    return result;

}

void EControllerQtTree::slotCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
{
    this->m_selectedEItem = this->getEItemByTreeItemPtr(current);
    this->selectItem(this->m_selectedEItem);

    this->disselectItem(this->getEItemByTreeItemPtr(previous));

    // this->getEItemByTreeItemPtr(previous);
}


void EControllerQtTree::handleCommand(const ECommandPtr& command)
{
    // ELOG_DEBUG("cmd.name=%s", command->getName().data());
    // if(command->getName() == "c:addItem" 
            // && command->getState() == ECommand::STATE::UNDO
            // && ifCmdSenderValid(command->getSender()))
    // {
        // long tagItem = command->getOrCreatMeta()->getProperty("tagItem")->value.to_intptr_t();
    // }
    // else if(command->getName() == "c:propertyChanged" 
            // && command->getState() == ECommand::STATE::UNDO
            // && ifCmdSenderValid(command->getSender()) )
    // {
    // }
    if(command->getName() == "c:refreshItem"
            && command->getState() == ECommand::STATE::NORMAL
            && command->getSenderName() != this->getName()
      ) 
    {
        this->handleCommandRefresh(command);
    }
}

void EControllerQtTree::handleCommandRefresh(const ECommandPtr& command)
{
    this->refresh();
}

void EControllerQtTree::buildConnect()
{
    QObject::connect(this->m_treeWidget, 
                     SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
                     this,
                     SLOT(slotCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))
                     );
}

void EControllerQtTree::clearConnect()
{
    QObject::disconnect(this->m_treeWidget, 
                     SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
                     this,
                     SLOT(slotCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))
                     );
}

// bool EControllerQtTree::handleEItem(EItemPtr item, int depth, EItemPtr parentItem)
// {
    // // ELOG_DEBUG("Name=%s,Depth=%d", item->getName().data(), depth);
    // // if item has related tree item
    // if(this->m_mapTag2TreeItem.find(item->getTag()) != this->m_mapTag2TreeItem.end())
    // {
        // EControllerTreeItem* treeItem = this->m_mapTag2TreeItem[item->getTag()];
        // this->synTreeItemAndEItem(item, treeItem);
        // return true;
    // }
    
    // //new a Tree Item
    // EControllerTreeItem* treeItem = new EControllerTreeItem;
    // treeItem->m_tag = item->getTag();
    // this->synTreeItemAndEItem(item, treeItem);

    // //set to map struct
    // this->m_mapTag2TreeItem[item->getTag()] = treeItem;
    // this->m_mapTag2EItem[item->getTag()] = item;

    // //link Tree Item
    // if(depth == 0)
    // {
        // this->m_treeWidget->addTopLevelItem(treeItem);
    // }
    // else
    // {
        // this->m_mapTag2TreeItem[parentItem->getTag()]->addChild(treeItem);
    // }

    // return true;
// }

// EItemPtr EControllerQtTree::getSelectedItem()
// {
    // if(this->m_selectedEItem == nullptr)
    // {
        // this->m_selectedEItem = this->m_rootEItem;
    // }

    // return this->m_selectedEItem;

// }

// void EControllerQtTree::setSelectedItem(EItemPtr item)
// {
    // this->m_selectedEItem=item;
// }

// void EControllerQtTree::addItem_deprected(long tagTypeItem)
// {
    // //get parent and check valid
    // EItemPtr parent = this->getSelectedItem();
    
    // if(parent == nullptr)
    // {
        // ELOG_ERROR("parent==nullptr");
        // return;
    // }

    // //find typeItem and call construction function
    // //then call handleEItem function
    // EItemPtr typeItem = EItemManager::instance()->getItemByTag(
            // EItemManager::instance()->getItemTypeRoot()
            // , tagTypeItem);

    // if(typeItem != nullptr)
    // {
        // EString funName = typeItem->getName() + "_Fun_factory";
        // EItemMetaFunctionPtr fun = typeItem->getOrCreatMeta()->getFunction(funName);
        // if(fun != nullptr)
        // {
            // ELOG_DEBUG("funName=%s", fun->getName().data());
            // EVariant result;
            // fun->call(&result);
            // EItem* newItemRawPtr = (EItem*)result.to_intptr_t();
            // EItemPtr child(newItemRawPtr);
            // //TODO: Add judgment, if addChild return true, then contiue, if addChild return false, then do not add item to tree.
            // parent->addChild(child);
            // this->handleEItem(child, -1, parent);

            // //push the additem command
            // ECommandPtr newCmd = NewSmartPtr(ECommand)();
            // newCmd->setSender( (intptr_t)this );
            // newCmd->setName("c:addItem");
            // newCmd->getOrCreatMeta()->addProperty("tagItem", child->getTag());
            // ECommandManager::instance()->pushECommand(newCmd);
        // }
    // }

    // //try to expand the parent item
    // QTreeWidgetItem* treeItem = this->getTreeItemByEItemPtr(parent);
    // if(treeItem != NULL)
    // {
        // treeItem->setExpanded(true);
    // }


// }
// void EControllerQtTree::deleteItem(long tag)
// {
    // QMap<long, EControllerTreeItem*>::iterator it = this->m_mapTag2TreeItem.find(tag);
    // QMap<long, EItemPtr>::iterator itItem = this->m_mapTag2EItem.find(tag);
    // if(it != this->m_mapTag2TreeItem.end())
    // {
        // EControllerTreeItem* treeItem = this->m_mapTag2TreeItem[tag];
        // EItemPtr item = this->m_mapTag2EItem[tag];

        // EControllerTreeItem* treeParent = (EControllerTreeItem*)treeItem->parent();
        // treeParent->removeChild(treeItem);

        // EItemPtr itemParent = this->m_mapTag2EItem[treeParent->m_tag];
        // itemParent->removeChild(item);

        // this->m_mapTag2EItem.erase(itItem);
        // this->m_mapTag2TreeItem.erase(it);
    // }
// }
// void EControllerQtTree::copyItem(long tag)
// {
    // QMap<long, EControllerTreeItem*>::iterator it = this->m_mapTag2TreeItem.find(tag);
    // QMap<long, EItemPtr>::iterator itItem = this->m_mapTag2EItem.find(tag);
    // if(it != this->m_mapTag2TreeItem.end())
    // {
        // EItemPtr item = this->m_mapTag2EItem[tag];
        // EString className = item->getOrCreatMeta()->getClassName();
        
        // //find typeItem to construct new EItem;
        // EItemPtr typeItem = EItemManager::instance()->getItemByName(
                // EItemManager::instance()->getItemTypeRoot()
                // , className);
        // //call the _Fun_factory
        // EItemPtr newItemPtr;
        // if(typeItem != nullptr)
        // {
            // EString funName = typeItem->getName() + "_Fun_factory";
            // EItemMetaFunctionPtr fun = typeItem->getOrCreatMeta()->getFunction(funName);
            // if(fun != nullptr)
            // {
                // EVariant result;
                // fun->call(&result);
                // EItem* newItemRawPtr = (EItem*)result.to_intptr_t();
                // newItemPtr = EItemPtr(newItemRawPtr);
            // }
        // }

        // //get parent EItem and call addChild
        // //The reason that get parent EItem from ui's tree item not from EItem::getParent
        // //is: EItem's parent may not be more than one, bu ui's tree item is only one
        // EControllerTreeItem* treeItem = this->m_mapTag2TreeItem[tag];

        // EControllerTreeItem* treeParent = (EControllerTreeItem*)treeItem->parent();
        // if(treeParent != NULL && newItemPtr != nullptr)
        // {
            // EItemPtr parentItem = this->m_mapTag2EItem[treeParent->m_tag];
            // parentItem->addChild(newItemPtr);
            
            // this->handleEItem(newItemPtr, -1, parentItem);
        // }
    // }
// }

// void EControllerQtTree::selectItem(EItemPtr item)
// {
    // EController::selectItem(item);
    // // ECommandPtr newCmd = NewSmartPtr(ECommand)();
    // // newCmd->setSender( this->getTag() );
    // // newCmd->setSenderName("WidgetTree.EControllerQtTree");
    // // newCmd->setName("c:selectItem");
    // // newCmd->addChild(item);
    // // newCmd->setIfEnableUndo(false);
    // // ECommandManager::instance()->pushECommand(newCmd);
// }

// void EControllerQtTree::disSelectItem(EItemPtr item)
// {
// }
// EControllerTreeItem* EControllerQtTree::newTreeItemByEItemPtr(const EItemPtr& itemPtr)
// {
    // EControllerTreeItem* treeItem = new EControllerTreeItem;

    // treeItem->m_tag = itemPtr->getTag();

    // return treeItem;
// }

// void EControllerQtTree::synTreeItemAndEItem(const EItemPtr& itemPtr, EControllerTreeItem* treeItem)
// {
    // if(itemPtr->getName().isEmpty())
    // {
        // EString className = itemPtr->getOrCreatMeta()->getClassName();
        // EString name = className
                      // + "_" 
                      // + EString::number(this->checkItemTypeCount(className));
        // itemPtr->setName(name.data());
        // treeItem->setText(0, name.data());
    // }
    // else 
    // {
        // EString name = itemPtr->getName();
        // treeItem->setText(0, name.data());
    // }
// }

// int EControllerQtTree::checkItemTypeCount(const EString& className)
// {
    // int result = 0;
    // QMap<long, EItemPtr>::iterator it = this->m_mapTag2EItem.begin();
    // for(; it != this->m_mapTag2EItem.end(); it++)
    // {
        // EItemPtr item = it.value();
        // if( className == item->getOrCreatMeta()->getClassName())
        // {
            // result++;
        // }
    // }
    // return result;
// }
